﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IWMAG.Scripting.AST.ObjectModel;
using IWMAG.Scripting.Types;
using IWMAG.Scripting.AST.TerminalExpressions;
using IWMAG.Scripting.Interpreter;
using IWMAG.Scripting.Compiler.UserInfo;
using System.Diagnostics;

namespace IWMAG.Scripting.AST.Statements {
    internal class ReturnStatement : CodeStatement {
        public CodeExpression Value;

        public ReturnStatement(Compiler.Lexeme l, CodeExpression val)
            : base(l) {
            Value = val != null ? val : new VoidExpression(l);
        }

        public override void Verify(Helpers.CompileTable sym, List<Compiler.IUserInfo> error) {
            Value.Verify(sym, error);
            CodeType t = sym.Dealias(Value.TypeOf());

            // this not only gets the type expected of the return
            // but also tells the function we found a return
            CodeType u = sym.Lookahead[GetType()]() as CodeType;

            if (!sym.Lookahead.Contains(GetType())) {
                Debug.Fail("The return type was not populated by the function call. This should never happen.");
            } else if (!t.Equals(u)) {
                SendError(error, Rules.FunctionReturnsValueOfIncompatibleType, u.ToString(), t.ToString());
            }
        }

        public override IEnumerable<Continuation> Execute(Interpreter.ScriptEngine engine, Helpers.RuntimeTable sym) {
            if (!(Value is VoidExpression)) {
                Reference<RunValue> val = RunValue.NoValue;
                foreach (Continuation wait in Value.ValueOf(engine, sym, val)) yield return wait;
                sym.Passback[GetType()](val.ReferencedValue);
            }
            yield return new Continuation(Continuation.Token.Return);
        }
    }
}
